/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.appspot.ittrick.drive.trick.controller;

import com.appspot.ittrick.drive.trick.Constants;
import com.appspot.ittrick.drive.trick.DriveTrick;
import com.appspot.ittrick.drive.trick.api.DriveAPIService;
import com.appspot.ittrick.drive.trick.api.GoogleOauthAPIService;
import com.appspot.ittrick.drive.trick.bind.FileTransmissionVisibleBinding;
import com.appspot.ittrick.drive.trick.bind.MainProgressVisibleBinding;
import com.appspot.ittrick.drive.trick.custom.FolderTreeItem;
import com.appspot.ittrick.drive.trick.db.AccountMstEntity;
import com.appspot.ittrick.drive.trick.db.DBManager;
import com.appspot.ittrick.drive.trick.model.FileModel;
import com.appspot.ittrick.drive.trick.task.FileDownloadTask;
import com.appspot.ittrick.drive.trick.task.FileUploadTask;
import com.appspot.ittrick.drive.trick.task.GetGoogleAccountAboutTask;
import com.appspot.ittrick.drive.trick.task.GetRootFolderTask;
import com.appspot.ittrick.drive.trick.task.GoogleAddNewFileTask;
import com.appspot.ittrick.drive.trick.task.LaodFilesListTask;
import com.appspot.ittrick.drive.trick.task.LaodFolderListTask;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.services.drive.model.About;
import com.google.api.services.drive.model.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.HostServices;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;

/**
 *
 * @author takahara
 */
public class MainController extends AnchorPane implements Initializable {
    
    /**
     * MainController instance
     */
    private static MainController instance;

    @FXML
    private Label accontLabel;
    @FXML
    public TreeView<File> folderTreeView;
    @FXML
    private TableView<FileModel> fileTableView;
    @FXML
    public HBox progressIndicatorHBox;
    @FXML
    private TextField fileSearchTextField;
    @FXML
    private HBox fileTransmissionHbox;
    @FXML
    private Label fileTransmissionTitle;
    @FXML
    private Label transmissionFileNameLabel;
    @FXML
    private ProgressBar capacityProgressBar;
    @FXML
    private Label capacityLabel;
    private final String mailAddress;
    /**
     * 承認情報
     */
    public Credential credential;
    /**
     * Google Drive Service
     */
    private DriveAPIService driveService;

    /**
     * タスク
     */
    public LaodFilesListTask loadFileListTask = new LaodFilesListTask();
    public GetRootFolderTask getRootFolderTask = new GetRootFolderTask();
    public LaodFolderListTask laodFolderListTask = new LaodFolderListTask();
    public FileUploadTask fileUploadTask = new FileUploadTask();
    public FileDownloadTask fileDownloadTask = new FileDownloadTask();
    public GoogleAddNewFileTask googleAddNewFileTask = new GoogleAddNewFileTask();
    public GetGoogleAccountAboutTask getGoogleAccountAboutTask = new GetGoogleAccountAboutTask();

    /**
     * コンストラクタ
     * @param mailAddress
     */
    public MainController(String mailAddress) {
        setInstance();
        this.mailAddress = mailAddress;
        loadFXML();
    }

    /**
     * 初期化メソッド
     */
    private void loadFXML() {
        // ---------------------------------------------------
        // FXMLのロードと設定
        // ---------------------------------------------------
        FXMLLoader fxmlLoader = new FXMLLoader(DriveTrick.class.getResource("fxml/main.fxml"));
        fxmlLoader.setRoot(this);
        // 自分自身をコントロールとして設定
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    /**
     * initialize
     *
     * @param url
     * @param rb
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        try {
            // drive service の初期化
            credential = GoogleOauthAPIService.getCredentials(mailAddress);
            driveService = new DriveAPIService(credential);
            
            // -----------------------------------------------------------------
            // タスクの初期化
            // -----------------------------------------------------------------
            initGetGoogleAccountAboutTask();
            initLoadFileListTask();
            initGetRootFolderTask();
            initFileUploadTask();
            initFileDownloadTask();
            initGoogleAddNewFileTask();

            // -----------------------------------------------------------------
            // プログレスの初期化
            // -----------------------------------------------------------------
            progressIndicatorHBox.visibleProperty().bind(
                    new MainProgressVisibleBinding(getRootFolderTask, laodFolderListTask));
            fileTransmissionHbox.visibleProperty().bind(new FileTransmissionVisibleBinding(fileUploadTask, fileDownloadTask));
            
            // -----------------------------------------------------------------
            // ユーザー情報の初期化
            // -----------------------------------------------------------------
            getGoogleAccountAboutTask.run();
            AccountMstEntity accountMstEntity = DBManager.getAccountInfo(DBManager.getConn(), mailAddress);
            loadAccountInfo(accountMstEntity);
            
            // -----------------------------------------------------------------
            // テーブルの初期化
            // -----------------------------------------------------------------
            // テーブルPlaceholder非表示
            fileTableView.setPlaceholder(new Text(""));
//            fileTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
            // テーブルのドロップ設定
            initFileDrop();

            
            // ファイル検索イベント
            fileSearchTextField.setOnKeyPressed(new EventHandler<KeyEvent>() {
                @Override
                public void handle(KeyEvent t) {
                    if (t.getCode() == KeyCode.ENTER && !fileSearchTextField.getText().isEmpty()) {
                        loadFileListTask.loadSearchFiles(fileSearchTextField.getText());
                    }
                }
            });

        } catch (Exception ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * アカウントのロード
     */
    private void loadAccountInfo(AccountMstEntity accountMstEntity) throws IOException {
        
        getRootFolderTask.run();

        // ユーザー情報の取得と設定
        accontLabel.setText(accountMstEntity.name);
        
        if (accountMstEntity.pictureUrl != null) {
            ImageView imageView = new ImageView(DriveTrick.class.getResource("images/gdrive.png").toString());
            imageView.setFitHeight(50.0);
            imageView.setPreserveRatio(true);
            accontLabel.setGraphic(imageView);
        }
        
        // -----------------------------------------
        // クリックイベントの設定
        // -----------------------------------------
        accontLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {

                // マウスの左ボタンがクリックされた場合
                if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {

                    DriveTrick.getInstance().sendMenuController();
                }
            }
        });
    }

    /**
     * ファイルロードタスク初期化
     */
    private void initLoadFileListTask() {
        
        loadFileListTask.setOnRunning(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                ProgressIndicator pi = new ProgressIndicator();
                pi.setPrefWidth(20);
                pi.setPrefHeight(20);
                pi.setMaxWidth(20);
                pi.setMaxHeight(20);
                fileTableView.setPlaceholder(pi);
                fileTableView.getItems().setAll(new ArrayList());
            }
        });

        // ---------------------------------------------------------------------
        // サービスの正常処理イベント
        // ---------------------------------------------------------------------
        loadFileListTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {

                List<FileModel> fileList = (List<FileModel>) t.getSource().getValue();
                fileTableView.getItems().setAll(fileList);
                if(fileList.isEmpty()) {
                    fileTableView.setPlaceholder(new Text("ファイルがありません。"));
                }else {
                    fileTableView.setPlaceholder(new Text(""));
                }
            }
        });
    }
    
    /**
     * ルートフォルダ取得タスク初期化
     */
    private void initGetRootFolderTask() {

        // ---------------------------------------------------------------------
        // サービスの正常処理イベント
        // ---------------------------------------------------------------------
        getRootFolderTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {

                File rootFile = (File) t.getSource().getValue();
                FolderTreeItem rootItem = new FolderTreeItem(rootFile);
                rootItem.setExpanded(true);
                folderTreeView.setRoot(rootItem);
                
                // Rootのファイルリストをロードする
                loadFileListTask.loadFilesByFolderId(rootFile);
            }
        });
    }
    
    /**
     * アカウント情報取得タスク初期化
     */
    private void initGetGoogleAccountAboutTask() {
        
        // ---------------------------------------------------------------------
        // サービスの正常処理イベント
        // ---------------------------------------------------------------------
        getGoogleAccountAboutTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                About about = (About) t.getSource().getValue();
                
                double quotaBytesTotal = about.getQuotaBytesTotal() / (1024 * 1024 * 1024);
                double quotaBytesUsed = about.getQuotaBytesUsed();
                BigDecimal bd = new BigDecimal(quotaBytesUsed / (1024 * 1024 * 1024));
                double quotaBytesUsedG = bd.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

                capacityProgressBar.setProgress(quotaBytesUsedG / quotaBytesTotal);
                capacityLabel.setText(quotaBytesTotal - quotaBytesUsedG + " G");
            }
        });
    }
    
    /**
     * ファイルアップロードタスクの初期化
     */
    private void initFileUploadTask() {
        
        fileUploadTask.setOnRunning(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                fileTransmissionTitle.setText("アップロード中...");
            }
        });
        
        fileUploadTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {

                List<FileModel> fileModelList = (List<FileModel>) t.getSource().getValue();
                fileTableView.getItems().addAll(fileModelList);
            }
        });
        
        fileUploadTask.messageProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ov, String t, String t1) {
                transmissionFileNameLabel.setText(t1);
            }
        });
    }
    
    /**
     * ファイルアップロードタスクの初期化
     */
    private void initFileDownloadTask() {
        
        fileDownloadTask.setOnRunning(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                fileTransmissionTitle.setText("ダウンロード中...");
            }
        });
        
        fileDownloadTask.messageProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ov, String t, String t1) {
                transmissionFileNameLabel.setText(t1);
            }
        });
    }
    
    /**
     * ルートフォルダ取得タスク初期化
     */
    private void initGoogleAddNewFileTask() {

        // ---------------------------------------------------------------------
        // サービスの正常処理イベント
        // ---------------------------------------------------------------------
        googleAddNewFileTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {

                File file = (File) t.getSource().getValue();
                if (file != null) {
                    fileTableView.getItems().addAll(new FileModel(file));
                }
            }
        });
    }
    
    
    /**
     * メニュー画面に戻る
     */
    @FXML
    protected void goToMenuAction() {
        DriveTrick.getInstance().sendMenuController();
    }
    
    /**
     * リフレッシュ
     */
    @FXML
    protected void refreshAction() {
        loadFileListTask.reLoad();
    }
    
    /**
     * INFOサイトを開く
     */
    @FXML
    protected void showInfoSiteAction() {
        HostServices hostServices = DriveTrick.getInstance().getJavaFXHostServices();
        hostServices.showDocument(Constants.APP_INFO_SITE_URL);
    }
    
    /**
     * ファイル追加アクション
     */
    @FXML
    protected void addNewFileAction() {
        final AddGoogleNewFileController controller = new AddGoogleNewFileController();
        
        controller.createButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                Object fileType = controller.fileTypesGroup.getSelectedToggle().getUserData();
                DriveTrick.getInstance().closePopStage();
                googleAddNewFileTask.run(loadFileListTask.getfolderFile(), fileType);
            }

        });
        
        DriveTrick.getInstance().showPopStage(controller, "ファイル作成", 700, 420);
    }
    
    /**
     * ファイルドラッグの初期化
     */
    private void initFileDrop() {
        
        // ---------------------------------------------------------------------
        // ドラッグ中
        // ---------------------------------------------------------------------
        fileTableView.setOnDragOver(
                new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                event.acceptTransferModes(TransferMode.COPY);
            }
        });

        // ---------------------------------------------------------------------
        // ドラッグ実行
        // ---------------------------------------------------------------------
        fileTableView.setOnDragDropped(
                new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent e) {
                Dragboard db = e.getDragboard();
                
                List<java.io.File> fileList = db.getFiles();
                fileUploadTask.run(loadFileListTask.getfolderFile().getId(), fileList);
                
                e.setDropCompleted(true);
            }
        });
        
    }
    
    /**
     * 親フォルダーへアクション
     */
    @FXML
    protected void showParentAction() {
        loadFileListTask.loadParentDriFiles();
    }
    
    /**
     * 共有されているファイルの表示
     */
    @FXML
    protected void showSharedWithMeFilesAction() {
        loadFileListTask.loadSharedWithMeFiles();
    }
    
    /**
     * ゴミ箱内のファイルの表示
     */
    @FXML
    protected void showTrashFilesAction() {
        loadFileListTask.loadTrashFiles();
    }
    
    /**
     * Get DriveTrick Instance
     *
     * @return
     */
    public static MainController getInstance() {
        return instance;
    }
    
    /**
     * インスタンスの設定
     */
    private void setInstance() {
        instance = this;
    }
    
    public void setDriveService(DriveAPIService driveService) {
        this.driveService = driveService;
    }
    
    public DriveAPIService getDriveService() {
        return this.driveService;
    }
}
